import { Component, OnInit, Input, ElementRef, ViewChild, TemplateRef, Inject, Optional } from '@angular/core';
import { ActivatedRoute, NavigationEnd } from '@angular/router';

import { BaseView } from '../../core/view/base-view';
import { NavTab } from './nav-tab';
import { NavTabService } from '../../core/service/nav-tab.service';
import { pick, isBoolean, isNumber } from '../../util';
import { NzContextMenuService, NzDropdownMenuComponent } from 'ng-zorro-antd';
import { HOME_PATH } from '../../layout/keys';
import { NAV_TAB_DISPLAY_MAX_COUNT, NAV_TAB_DISABLE_LOAD, SPA } from '../../core/keys';
import { MenuService } from '../../core/service/menu.service';

@Component({
  selector: 'bz-nav-tab',
  templateUrl: './nav-tab.component.html'
})
export class NavTabComponent<U, B, S> extends BaseView<U, B, S> implements OnInit {

  @ViewChild('container', { static: true }) containerRef: ElementRef;
  /** 右键菜单 */
  @ViewChild('contextMenu', { static: true }) contextMenuRef: NzDropdownMenuComponent;
  tabList: NavTab[] = [];
  activeIndex = -1;
  leftArrowEnd = false;
  rightArrowEnd = false;
  showArrow = false;
  activeCloseRightTab = false;
  activeRefreshTab = false;
  /** 右键菜单激活时的tab项 */
  currContextMenuTab: any;
  /** 该字段表示在现有tab之间切换时发生的路由变化时的新url，一般是用户通过操作tab页产生的路由变化 */
  private willVisitUrl: string;
  /** 首次激活路由 */
  private firstActive = true;
  private ACE: any; //

  constructor(
    @Inject(NAV_TAB_DISPLAY_MAX_COUNT) private maxDisplayCount,
    @Inject(NAV_TAB_DISABLE_LOAD) private disableLoad,
    @Inject(HOME_PATH) private homePath: string,
    @Optional() @Inject(SPA) private spa: boolean,
    private navTabService: NavTabService<B>,
    private activatedRoute: ActivatedRoute,
    private nzContextMenuService: NzContextMenuService,
    private menuService: MenuService<B, S>
  ) {
    super();
    this.spa = window.self === window.top ? (this.spa === null ? false : this.spa) : true;
    this.ACE = window.self === window.top ? window['ACE'] : window.top['ACE'];
  }
  ngOnInit() {
    this.load();
    this.router.events.subscribe(e => {
      if (!(e instanceof NavigationEnd)) { return; }
      this.setActiveTab();
    });
    this.broadcastService.subscribe(<any>'CloseNavTab', () => {
      if (this.spa && this.ACE) {
        this.ACE.WIDGET.layout.removeTab(JSON.parse(window.top.localStorage.ACE_WIDGET_MAIN_CURRENT_TABS));
      } else {
        this.close(this.tabList[this.activeIndex], this.activeIndex);
      }
    });
    this.broadcastService.subscribe(<any>'RefreshNavTab', () => {
      this.refresh();
    });
    this.broadcastService.subscribe(<any>'NavTabTitle', (e) => {
      if (!e) {
        return;
      }
      const activeTab = this.tabList[this.activeIndex];
      if (activeTab && activeTab.title !== e) {
        setTimeout(() => {
          this.tabList[this.activeIndex].title = e;
          this.saveNavTab();
        });
      } else if (this.activeIndex === -1 && this.tabList.length > 0) {
        setTimeout(() => {
          this.tabList[0].title = e;
          this.saveNavTab();
        });
      }
      this.containerRef.nativeElement.addEventListener('mousewheel', this.scroll(e), { passive: true });
    });
    this.broadcastService.subscribe(<any>'BackNavTab', (e) => {
      const nav = this.tabList[this.activeIndex];
      if (nav.history[0]) {
        this.back(nav);
      } else {
        this.close(this.tabList[this.activeIndex], this.activeIndex);
      }
    });
    this.setActiveTab();
  }
  setActiveTab() {
    const snapshot = this.activatedRoute.snapshot;
    // 路由定义时指明不需要复用，该处不在为其显示tab页签
    if (snapshot.data.disableReuse) {
      return;
    }
    const target = snapshot.queryParams.target;
    const lastNav = this.tabList[this.activeIndex];
    const url = this.navTabService.parseUrl(snapshot);
    const queryParams = pick(snapshot.queryParams, '** -target -_fixed -_closeable');
    const menuData = this.menuService.getPageMenu().get(url);
    // 获取页签标题
    const title = snapshot.data.title || (menuData && menuData.name) || 'new tab ';
    const index = this.tabList.findIndex((t) => {
      const _queryParams = pick(t.queryParams, '** -target -_fixed -_closeable');
      return t.url === url && JSON.stringify(queryParams) === JSON.stringify(_queryParams);
    });
    const tab = index === -1 ? new NavTab(url, title, pick(snapshot.queryParams, '** -target')) : this.tabList[index];
    // 用户主动切换tab页或者用户关闭当前tab页或者刷新当前页或者从404页面跳转回来的或者首次打开页面
    if (this.willVisitUrl === url || this.navTabService.focusRefreshLeafRoute || this.firstActive || this.activeIndex === -1) {
      if (index === -1) {
        // this.tabList.push(tab);
        this.updateTabList('push', tab);
        this.activeIndex = this.tabList.length - 1;
      } else {
        this.activeIndex = index;
      }
    } else if (target === 'head' && index === -1) {
      // 主动设置target=head
      if (tab.fixed) {
        // this.tabList.unshift(tab);
        this.updateTabList('unshift', tab);
        this.activeIndex = 0;
      } else {
        const firstNoFixed = this.tabList.findIndex((t) => !t.fixed);
        if (firstNoFixed === -1) {
          // this.tabList.push(tab);
          this.updateTabList('push', tab);
          this.activeIndex = this.tabList.length - 1;
        } else {
          // this.tabList.splice(firstNoFixed, 0, tab);
          this.updateTabList('splice', firstNoFixed, 0, tab);
          this.activeIndex = firstNoFixed;
        }
      }
    } else if (target === 'replace' || target === 'back') {
      if (index !== -1) {
        this.tabList.splice(index, 1);
        const i = index > this.activeIndex ? this.activeIndex : this.activeIndex - 1;
        this.tabList.splice(i, 1, tab);
        this.activeIndex = i;
      } else {
        this.tabList.splice(this.activeIndex, 1, tab); // 移除tab时不移除缓存
      }
      // 保存tab页浏览记录
      if (lastNav) {
        // 在当前tab页面打开新页面
        if (target === 'replace') {
          lastNav.history.unshift({ url: lastNav.url, queryParams: lastNav.queryParams });
        } else if (target === 'back') { // 返回在当前tab页面之前的历史页面，如果找不到则关闭当前页面
          lastNav.history.shift();
        }
        this.tabList[this.activeIndex].history = lastNav.history;
        lastNav.history = [];
      }
      this.updateTabList();
    } else if (tab.fixed) {
      const firstNoFixed = this.tabList.findIndex((t) => {
        return t.fixed;
      });
      if (index === -1) {
        this.tabList.splice(firstNoFixed + 1, 0, tab);
        this.activeIndex = firstNoFixed + 1;
      } else if (index <= firstNoFixed) {
        this.activeIndex = firstNoFixed;
      } else {
        this.tabList.splice(index, 1);
        this.tabList.splice(firstNoFixed + 1, 0, tab);
        this.activeIndex = firstNoFixed + 1;
      }
      this.updateTabList();
    } else {
      if (index !== -1) {
        this.activeIndex = index;
      } else if (target === 'tail') {
        // this.tabList.push(tab);
        this.updateTabList('push', tab);
        this.activeIndex = this.tabList.length - 1;
      } else {
        // this.tabList.splice(this.activeIndex + 1, 0, tab);
        this.updateTabList('splice', this.activeIndex + 1, 0, tab);
        this.activeIndex++;
      }
    }
    this.firstActive = false;
    this.navTabService.focusRefreshLeafRoute = false;
    this.willVisitUrl = null;
    this.tabList.forEach(t => t.active = false);
    this.tabList[this.activeIndex].active = true;
    this.saveNavTab();
    if (lastNav && this.tabList[this.activeIndex] !== lastNav) {
      lastNav.firstVisit = false;
    }
    this.ngZone.runOutsideAngular(() => {
      setTimeout(() => {
        const tabItem = this.containerRef.nativeElement.querySelector(`.tab-item:nth-child(${this.activeIndex + 1})`);
        if (tabItem) {
          tabItem.scrollIntoView();
        }
        this.updateScrollBar(0);
      }, 300);
    });
  }

  switchTab(tab) {
    if (tab.active) {
      return;
    }
    this.willVisitUrl = tab.url;
    this.ngZone.run(() => {
      this.router.navigate([tab.url], { queryParams: tab.queryParams });
    });
  }

  copyTab(tab) {
    // 新开页签
    const newTab = JSON.parse(JSON.stringify(tab));
    newTab.queryParams._t = Date.now();
    this.willVisitUrl = newTab.url;
    this.ngZone.run(() => {
      this.router.navigate([newTab.url], { queryParams: newTab.queryParams });
    });
  }

  close(tab, index) {
    // 关闭当前页签
    if (tab.active) {
      this.navTabService.willRemove(tab.url);
      let activeIndex, activeTab;
      if (index === 0) {
        activeTab = this.tabList[1];
        activeIndex = 0;
      } else {
        activeTab = this.tabList[index - 1];
        activeIndex = index - 1;
      }
      if (activeTab) {
        this.activeIndex = activeIndex;
        this.willVisitUrl = activeTab.url;
        this.ngZone.run(() => {
          this.router.navigate([activeTab.url], { queryParams: activeTab.queryParams });
        });
      } else {
        this.activeIndex = -1;
        this.ngZone.run(() => {
          this.router.navigateByUrl(this.baseInfo.homePath || '/404');
        });
      }
    } else {// 关闭其他页签
      this.navTabService.remove([tab.url]);
      this.activeIndex = this.activeIndex > index ? this.activeIndex - 1 : this.activeIndex;
    }
    this.tabList.splice(index, 1);
    this.saveNavTab();
  }

  closeOtherTab(tab?) {
    const currTab = tab || this.currContextMenuTab;
    const closeTabs = [];
    const openTabs = [];
    const currTabIndex = this.tabList.indexOf(currTab);
    this.tabList.forEach((t) => {
      if (t !== currTab && t.closeable) {
        closeTabs.push(t);
      } else {
        openTabs.push(t);
      }
    });
    this.navTabService.remove(closeTabs.map(t => t.url));
    this.tabList = openTabs;
    this.saveNavTab();
    this.closeContextMenu();
    if (this.activeIndex !== currTabIndex) {
      this.activeIndex = -1;
      this.ngZone.runOutsideAngular(() => {
        setTimeout(() => {
          this.switchTab(currTab);
        }, 500);
      });
    } else {
      this.activeIndex = this.tabList.indexOf(currTab);
    }
  }

  refresh() {
    const activeTab = this.tabList[this.activeIndex];
    if (!activeTab) {
      return;
    }
    this.navTabService.focusRefreshLeafRoute = true;
    const onSameUrlNavigation = this.router.onSameUrlNavigation;
    this.router.onSameUrlNavigation = 'reload';
    this.ngZone.run(() => {
      this.router.navigate([activeTab.url], { queryParams: activeTab.queryParams });
    });
    this.router.onSameUrlNavigation = onSameUrlNavigation;
    if (this.ACE && this.spa) { this.ACE.WIDGET.LAYOUT.SPARELOAD(); }
  }

  back(tab) {
    if (tab === this.tabList[this.activeIndex]) {
      const nav = this.tabList[this.activeIndex].history[0];
      this.ngZone.run(() => {
        this.router.navigate([nav.url], { queryParams: { target: 'back', ...nav.queryParams } });
      });
    }
  }

  scroll(e) {
    if (isNumber(e.wheelDelta)) {
      this.updateScrollBar(e.wheelDelta > 0 ? 50 : -50);
    } else if (isNumber(e.detail)) {
      this.updateScrollBar(e.detail > 0 ? 50 : -50);
    }
  }

  updateScrollBar(offset: boolean | number) {
    if (this.containerRef.nativeElement.scrollWidth === this.containerRef.nativeElement.clientWidth) {
      this.showArrow = false;
      return;
    }
    this.showArrow = true;
    if (isBoolean(offset)) {
      this.containerRef.nativeElement.scrollLeft = offset === true ? 0 : 1000000;
    } else {
      this.containerRef.nativeElement.scrollLeft += offset;
    }
    if (this.containerRef.nativeElement.scrollLeft === 0) {
      this.leftArrowEnd = true;
      this.rightArrowEnd = false;
    } else if (this.containerRef.nativeElement.scrollLeft >= this.containerRef.nativeElement.scrollWidth - this.containerRef.nativeElement.clientWidth) {
      this.rightArrowEnd = true;
      this.leftArrowEnd = false;
    } else {
      this.leftArrowEnd = this.rightArrowEnd = false;
    }
  }

  showContextMenu($event: MouseEvent, tab) {
    this.closeContextMenu();
    this.currContextMenuTab = tab;
    this.activeCloseRightTab = this.tabList.indexOf(tab) < this.tabList.length - 1;
    this.activeRefreshTab = this.tabList.indexOf(tab) === this.activeIndex;
    this.nzContextMenuService.create($event, this.contextMenuRef);
  }

  closeRightTab(tab?) {
    const currTab = tab || this.currContextMenuTab;
    let currTabIndex = -1;
    const closeTabs = [];
    const openTabs = [];
    this.tabList.forEach((t, i) => {
      if (t === currTab) {
        currTabIndex = i;
        openTabs.push(t);
      } else if (currTabIndex !== -1 && t.closeable) {
        closeTabs.push(t);
      } else {
        openTabs.push(t);
      }
    });

    this.navTabService.remove(closeTabs.map(t => t.url));
    this.tabList = openTabs;
    this.saveNavTab();
    this.closeContextMenu();
    if (this.activeIndex !== currTabIndex) {
      this.activeIndex = -1;
      this.ngZone.runOutsideAngular(() => {
        setTimeout(() => {
          this.switchTab(currTab);
        }, 500);
      });
    } else {
      this.activeIndex = this.tabList.length - 1;
    }
  }

  closeAllTab() {
    const closeTabs = [];
    const openTabs = [];
    this.tabList.forEach((t, i) => {
      if (t.closeable) {
        closeTabs.push(t);
      } else {
        openTabs.push(t);
      }
    });
    this.navTabService.remove(closeTabs.map(t => t.url));
    this.tabList = openTabs;
    this.activeIndex = -1;
    this.saveNavTab();
    this.closeContextMenu();
    if (openTabs.length > 0) {
      this.ngZone.runOutsideAngular(() => {
        setTimeout(() => {
          this.switchTab(openTabs[0]);
        }, 500);
      });
    } else {
      this.ngZone.run(() => {
        this.router.navigate([this.homePath]);
      });
    }
  }

  switchFixTab(tab?) {
    const currTab = tab || this.currContextMenuTab;
    const activeTab = this.tabList[this.activeIndex];
    const currTabIndex = this.tabList.indexOf(currTab);
    this.tabList.splice(currTabIndex, 1);
    for (let i = 0; i < this.tabList.length; i++) {
      if (!this.tabList[i].fixed) {
        this.tabList.splice(i, 0, currTab);
        break;
      } else if (i === this.tabList.length - 1) {
        this.tabList.push(currTab);
        break;
      }
    }
    if (this.tabList.length === 0) {
      this.tabList.push(currTab);
    }
    currTab.fixed = !currTab.fixed;
    this.activeIndex = this.tabList.indexOf(activeTab);
    this.closeContextMenu();
  }

  refreshTab() {
    this.closeContextMenu();
    this.ngZone.runOutsideAngular(() => {
      setTimeout(() => {
        this.refresh();
      }, 500);
    });
  }
  private closeContextMenu() {
    if (this.contextMenuRef) {
      this.nzContextMenuService.close();
    }
  }
  private load() {
    if (this.disableLoad) {
      return;
    }
    const list = this.getNavTab();
    list.forEach((tab: NavTab, i) => {
      if (tab) {
        tab.active = false;
      }
    });
    this.tabList = list;
  }
  private saveNavTab() {
    this.storeService.setItem(<any>'NavTab', {
      // 这里根据具体系统数据结构获取当前用户唯一识别id
      key: this.baseInfo.navTabStoreKey,
      list: this.tabList.filter(t => !!t.title)
    });
  }
  private getNavTab(): any[] {
    // tslint:disable-next-line:prefer-const
    let { key, list } = <any>(this.storeService.getItem(<any>'NavTab') || {});
    if (!Array.isArray(list)) {
      list = [];
    }
    if (list.length > this.maxDisplayCount) {
      list.length = this.maxDisplayCount;
    }
    // 这里根据具体系统数据结构获取当前用户唯一识别id
    return this.baseInfo.navTabStoreKey === key ? list : [];
  }
  private updateTabList(type?: 'push' | 'unshift' | 'splice', ...args) {
    if (type) {
      (this.tabList[type] as any).apply(this.tabList, args);
    }
    if (this.tabList.length > this.maxDisplayCount) {
      this.tabList.length = this.maxDisplayCount;
      this.loggerService.warn('nav-tab Exceed the maximum limit ' + this.maxDisplayCount);
    }
  }
}
